<template>
  <div id="map" @click="toPage"/>
</template>
<script>
import * as THREE from '@/assets/three.js/jms/three.module.js'
// import { OrbitControls } from '@/assets/three.js/jms/OrbitControls.js'
import { CSS2DRenderer, CSS2DObject } from '@/assets/three.js/jms/CSS2DRenderer.js';
import * as d3 from 'd3'
import mapData from './shijiazhuang.json'
export default {
  name: 'AreaMap',
  data() {
    return {
      renderer: null,
      labelRenderer: null,
      scene: null,
      camera: null,
      raycaster: null,
      mouse: null,
      container: null,
      regionInfo: null,
      parkList: [
        { lng: 114.487345, lat: 37.973843, name: '大侠停车场' },
        { lng: 113.927345, lat: 38.3738430000001, name: '平山停车场' },
        { lng: 114.88142703125, lat: 38.0297585273438, name: '幽灵停车场' }
      ],
      activeInstersect: [],
      // parkPng: require('@/assets/park.png'),
      parkPng: require('@/assets/bigDataSourceImage/未标题-1.gif'),
      depth: 0.5
    }
  },
  mounted() {
    this.init();
  },
  methods: {
    toPage() {
      this.$emit('toPage')
    },
    /**
		 * 初始化
		 */
    init() {
      this.container = document.getElementById('map');
      this.regionInfo = document.createElement('div');
      this.regionInfo.id = 'regionInfo';
      this.container.appendChild(this.regionInfo);

      // 渲染器
      this.renderer = new THREE.WebGLRenderer({
			  antialias: true, // true/false表示是否开启反锯齿
			  alpha: true // true/false 表示是否可以设置背景色透明
      })
      this.renderer.setPixelRatio(window.devicePixelRatio)
      this.renderer.setSize(this.container.offsetWidth, this.container.offsetHeight);
      this.container.appendChild(this.renderer.domElement);

      //	label渲染器
      this.labelRenderer = new CSS2DRenderer();
      this.labelRenderer.setSize(this.container.offsetWidth, this.container.offsetHeight);
      this.labelRenderer.domElement.style.position = 'absolute';
      this.labelRenderer.domElement.style.top = '0px';
      this.container.appendChild(this.labelRenderer.domElement);

      // 场景
      this.scene = new THREE.Scene();

      //	相机
      // this.camera = new THREE.PerspectiveCamera(45, this.container.offsetWidth / this.container.offsetHeight, 0.1, 1000);
      this.camera = new THREE.PerspectiveCamera(45, this.container.offsetWidth / this.container.offsetHeight * 0.6, 0.1, 1000);
      // this.camera.position.set(0, 0, 150);
      this.camera.position.set(0, -3, 5);
      this.camera.lookAt(0, 0, 0);
      // this.buildAuxSystem();	// 构建辅助系统: 网格和坐标
      this.setLight();	//	光源
      this.initMapData();	//	初始化地图数据
      this.setRaycaster();	//	模型选中与信息显示
      this.setResize();	//	监听窗口尺寸
      this.animate();	//	渲染
    },
    /**
		 * 初始化地图数据
		 */
    initMapData() {
      // 墨卡托投影转换
      const projection = d3.geoMercator().center([114.56, 38.055]).scale(150).translate([0, 0]);
      // 建一个空对象存放对象
      const map = new THREE.Object3D();

      mapData.features.forEach(elem => {
			  // 定一个省份3D对象
			  const region = new THREE.Object3D();
			  // 每个的 坐标 数组
			  const coordinates = elem.geometry.coordinates;
			  // 循环坐标数组
			  coordinates.forEach(multiPolygon => {
			    multiPolygon.forEach(polygon => {
            const shape = new THREE.Shape();

            //	线
            const lineMaterial = new THREE.LineBasicMaterial({
              color: '#2275a0',
              linewidth: 1
            });
            const lineGeometry = new THREE.Geometry();
            for (let i = 0; i < polygon.length; i++) {
              const [x, y] = projection(polygon[i]);
              if (i === 0) {
						  shape.moveTo(x, -y);
              }
              shape.lineTo(x, -y);
              lineGeometry.vertices.push(new THREE.Vector3(x, -y, this.depth + 0.01));
            }
            // let points = new THREE.Points(lineGeometry, new THREE.PointsMaterial({ color: 0x00ff66, size: 0.1 }));
            // this.scene.add(points);

            //	面
            const geometry = new THREE.ExtrudeGeometry(shape, { depth: this.depth, bevelEnabled: false });
            const material = new THREE.MeshBasicMaterial({
              color: '#003461',
			  transparent: true,	//	透明的
			  opacity: 0.9
            });
            const material1 = new THREE.MeshBasicMaterial({
              color: '#003753',
              transparent: true,	//	透明的
              opacity: 0.95
            });

            const shapeMesh = new THREE.Mesh(geometry, [material, material1]);
            const shapeLine = new THREE.Line(lineGeometry, lineMaterial);
            region.add(shapeMesh);
            region.add(shapeLine);
			    })
			  })

			  // 将geo的属性放到地区模型中
			  region.properties = elem.properties;
			  if (elem.properties.centroid) {
			    const [x, y] = projection(elem.properties.centroid);
			    region.properties._centroid = [x, y];
			  }

			  map.add(region);
      })

      this.scene.add(map);	//	地图加载到场景中

      //* ***********停车场坐标
      this.parkList.forEach((park) => {
        const pos = projection([park.lng, park.lat]);

        const geometry = new THREE.Geometry();
        geometry.vertices.push(new THREE.Vector3(pos[0], -pos[1], this.depth + 0.01));
        const material = new THREE.PointsMaterial({ color: 0xff421c, size: 0.01 });
        const points = new THREE.Points(geometry, material);

        const img = document.createElement('img');
        img.src = this.parkPng;
        img.style.width = '3.5em';
        // img.style.width = '10em'

        const label = document.createElement('label');
        label.style.color = '#FFFFFF';
        label.style.position = 'relative';
        label.style.left = '-0.6em';
        label.style.bottom = '0.5em';
        label.textContent = park.name;

        const parkDiv = document.createElement('div');
        parkDiv.className = 'label';
        parkDiv.appendChild(img);
        parkDiv.appendChild(label);
        const parkLabel = new CSS2DObject(parkDiv);
        parkLabel.position.set(pos[0], -pos[1], this.depth + 0.01);
        points.add(parkLabel);

        this.scene.add(points);
      })
    },
    /**
		 * 光源
		 */
    setLight() {
			 var pointLight = new THREE.PointLight(0xffffff, 10, 0);
			 pointLight.position.set(0, 0, 30);
			 pointLight.add(new THREE.Mesh(new THREE.SphereBufferGeometry(0.001, 16, 8), new THREE.MeshBasicMaterial({ color: 0xffffff })));
			 this.scene.add(pointLight);

      const ambientLight = new THREE.AmbientLight(0xffffff, 0.1);	// 环境光
      this.scene.add(ambientLight);
    },
    /**
		* 构建辅助系统: 网格和坐标
		*/
    buildAuxSystem() {
      const axisHelper = new THREE.AxesHelper(2000);
      this.scene.add(axisHelper);
    },
    /**
		 * 显示地区的信息
		 */
    createRegionInfo() {
		  if (this.activeInstersect.length !== 0 && this.activeInstersect[0].object.parent.properties.name) {
		    var properties = this.activeInstersect[0].object.parent.properties;

		    this.regionInfo.textContent = properties.name;

		    this.regionInfo.style.visibility = 'visible';
		  } else {
		    this.regionInfo.style.visibility = 'hidden';
		  }
    },
    /**
		 * 模型选中与信息显示
		 */
    setRaycaster() {
		  this.raycaster = new THREE.Raycaster();
		  this.mouse = new THREE.Vector2();
		  const eventOffset = {};
		  var _this = this;

		  const domToTop = this.container.getBoundingClientRect().top // dom 的顶边到视口顶部的距离
		  const domToLeft = this.container.getBoundingClientRect().left // dom 的左边到视口左边的距离
		  const domToBottom = this.container.getBoundingClientRect().bottom // dom 的底边到视口顶部的距离
		  const domToRight = this.container.getBoundingClientRect().right // dom 的右边到视口左边的距离
		  function onMouseMove(event) {
        _this.mouse.x = ((event.clientX - domToLeft) / _this.container.offsetWidth) * 2 - 1;
        _this.mouse.y = -((event.clientY - domToTop) / _this.container.offsetHeight) * 2 + 1;
        // _this.mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
        // _this.mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;

        eventOffset.x = event.clientX;
        eventOffset.y = event.clientY;
        _this.regionInfo.style.left = eventOffset.x - domToLeft + 2 + 'px';
        _this.regionInfo.style.top = eventOffset.y - domToTop + 2 + 'px';
      }

      this.container.addEventListener('mousemove', onMouseMove, false);
      // window.addEventListener('mousemove', onMouseMove, false);
    },
    /**
		* 渲染
		*/
    animate() {
      requestAnimationFrame(this.animate.bind(this));
      this.raycaster.setFromCamera(this.mouse, this.camera);

      var intersects = this.raycaster.intersectObjects(this.scene.children, true);
      // 将上一次选中的恢复颜色
      if (this.activeInstersect && this.activeInstersect.length > 0) {
			  this.activeInstersect.forEach(element => {
			    element.object.material[0].color.set('#003461');
			    element.object.material[1].color.set('#003753');
			  });
      }

      this.activeInstersect = []; // 设置为空
      for (var i = 0; i < intersects.length; i++) {
        if (intersects[i].object.material && intersects[i].object.material.length === 2) {
				  this.activeInstersect.push(intersects[i]);
				  intersects[i].object.material[0].color.set(0x084981);
				  intersects[i].object.material[1].color.set(0x084981);
				  break; // 只取第一个
        }
      }

      this.createRegionInfo();	// 显示地区的信息

      this.renderer.render(this.scene, this.camera);
      this.labelRenderer.render(this.scene, this.camera);
    },
    /**
		 * 监听窗口尺寸
		 */
    setResize() {
      const _this = this;
      window.addEventListener('resize', function() {
        _this.renderer.setSize(_this.container.offsetWidth, _this.container.offsetHeight);
        _this.labelRenderer.setSize(_this.container.offsetWidth, _this.container.offsetHeight);
      })
    }
  }
}
</script>

<style scoped>
  * {
    margin: 0;
    padding: 0;
  }
	#map {
		position: relative;
		height: 100%;
		border: 1px solid transparent;
		border-image-source: url('../../../../assets/bigDataSourceImage/box1.png');
		border-image-slice: 26 26 26 26;
		border-image-repeat: stretch;
		border-image-width: 26px;
		box-sizing: border-box;
		margin-top: 4px;
		/* padding: 1.4em; */
	}
	/deep/ #regionInfo {
	  position: absolute;
	  z-index: 2;
	  /* background: white; */
	  padding: 10px;
	  color: aqua;
	  visibility: hidden;
	}

</style>
